home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / xdme_1.84_src.lha / XDME / Src / search.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-04  |  16.0 KB  |  676 lines

  1. /******************************************************************************
  2.  
  3.     MODUL
  4.     $Id: search.c 1.3 1994/09/09 12:31:30 digulla Exp digulla $
  5.  
  6.     DESCRIPTION
  7.     Inherits all the search/replace stuff for DME
  8.  
  9.     HISTORY
  10.     28. May 1992    ada created
  11.     $Log: search.c $
  12.  * Revision 1.3  1994/09/09  12:31:30  digulla
  13.  * added new style Prototypes, DEFCMD and DEFHELP
  14.  *
  15.  * Revision 1.2  1994/08/19  14:07:15  digulla
  16.  * some reformatting
  17.  * fixed some minor bugs in search_operation
  18.  *
  19.  * Revision 1.1  1994/08/14  12:35:51  digulla
  20.  * Initial revision
  21.  *
  22.  
  23. ******************************************************************************/
  24.  
  25. /* Includes */
  26. #include "defs.h"
  27. #define MYDEBUG     0
  28. #include <debug.h>
  29.  
  30. /* Globale Variable */
  31.  
  32. /* Interne Defines & Strukturen */
  33.  
  34. /* Interne Variable */
  35. /*static*/ UBYTE Fstr[MAXLINELEN]; /* PATCH_NULL - commented out for spcvars */
  36. /*static*/ UBYTE Rstr[MAXLINELEN]; /* PATCH_NULL - commented out for spcvars */
  37. static char Srch_sign;
  38. static char Doreplace;
  39.  
  40. /* Interne Prototypes */
  41. static void search_operation (void);
  42.  
  43.  
  44. /*****************************************************************************
  45.  
  46.     NAME
  47.     do_findstr
  48.  
  49.     PARAMETER
  50.     av[0]        "find" or "replace"
  51.     av[1]        string to find or replace-string
  52.  
  53.     DESCRIPTION
  54.     Copies the search/replace-string to the internal buffer.
  55.  
  56. ******************************************************************************/
  57.  
  58. /*DEFHELP #cmd searchreplace FINDSTR string - Set the search string pattern */
  59. /*DEFHELP #cmd searchreplace REPSTR string - SET the replace string pattern */
  60.  
  61. DEFUSERCMD("repstr",  1, CF_VWM, void, do_findstr, (void),;)
  62. DEFUSERCMD("findstr", 1, CF_VWM, void, do_findstr, (void),)
  63. {
  64.     if (av[0][0] == 'f')    /* Check command name */
  65.     strcpy (Fstr, av[1]);    /* "find" */
  66.     else
  67.     strcpy (Rstr, av[1]);    /* "replace" */
  68. } /* do_findstr */
  69.  
  70.  
  71. /*****************************************************************************
  72.  
  73.     NAME
  74.     do_findr
  75.  
  76.     PARAMETER
  77.     av[0]    "findr", "nextr" or "prevr"
  78.     av[1]    find-string
  79.     av[2]    replace-string
  80.  
  81.     DESCRIPTION
  82.     Starts one find/replace-operation with both search- and replace-string
  83.     as arguments.
  84.  
  85. ******************************************************************************/
  86.  
  87. /*DEFHELP #cmd searchreplace FINDR s1 s2 - Set find and replace patterns and do one find&replace. */
  88. /*DEFHELP #cmd searchreplace NEXTR - find next occurance and replace */
  89. /*DEFHELP #cmd searchreplace PREVR - find previous occurance and replace */
  90.  
  91. DEFUSERCMD("findr", 2, 0, void, do_findr, (void),;)
  92. DEFUSERCMD("nextr", 0, 0, void, do_findr, (void),;)
  93. DEFUSERCMD("prevr", 0, 0, void, do_findr, (void),)
  94. {
  95.     Doreplace = 1;  /* Really replace */
  96.     Srch_sign = 1;  /* Search to EOF */
  97.  
  98.     switch (*av[0])
  99.     {
  100.     case 'f':
  101.         strcpy (Fstr, av[1]);    /* Set strings for "findr" */
  102.         strcpy (Rstr, av[2]);
  103.         break;
  104.  
  105.     case 'p':
  106.         Srch_sign = -1;        /* Search reverse */
  107.         break;
  108.     }
  109.  
  110.     search_operation (); /* Start search */
  111. } /* do_findr */
  112.  
  113.  
  114. /*****************************************************************************
  115.  
  116.     NAME
  117.     do_find
  118.  
  119.     PARAMETER
  120.     av[0]    "find", "next" or "prev"
  121.     av[1]    find-string if av[0] == find
  122.  
  123.     DESCRIPTION
  124.     Looks for a new string or searches forwards/backwars for the old one.
  125.  
  126. ******************************************************************************/
  127.  
  128. /*DEFHELP #cmd searchreplace FIND string - Set the search pattern to @{B}string@{UB} and do a NEXT */
  129. /*DEFHELP #cmd searchreplace NEXT - find next occurance of search pattern */
  130. /*DEFHELP #cmd searchreplace PREV - find previous occurance of search pattern */
  131.  
  132. DEFUSERCMD("find", 1, CF_VWM, void, do_find, (void),;)
  133. DEFUSERCMD("next", 0, CF_VWM, void, do_find, (void),;)
  134. DEFUSERCMD("prev", 0, CF_VWM, void, do_find, (void),)
  135. {
  136.     Doreplace = 0;  /* Don't replace */
  137.     Srch_sign = 1;
  138.  
  139.     switch (av[0][0])
  140.     {
  141.     case 'f':   /* Find: new string */
  142.         strcpy (Fstr, av[1]);
  143.     break;
  144.  
  145.     case 'p':   /* Search reverse */
  146.         Srch_sign = -1;
  147.     break;
  148.     }
  149.  
  150.     search_operation ();
  151. } /* do_find */
  152.  
  153.  
  154. /*****************************************************************************
  155.  
  156.     NAME
  157.     do_replace
  158.  
  159.     PARAMETER
  160.     av[0]    "replace"
  161.  
  162.     DESCRIPTION
  163.     Substitutes the next strlen(search-string) chars with the rep-string.
  164.     This command does no checking ! It always removes strlen(search-
  165.     string) chars and the rep-string is always inserted.
  166.  
  167. ******************************************************************************/
  168.  
  169. /*DEFHELP #cmd searchreplace REPLACE - replaces the next strlen(findstr) chars with repstr */
  170.  
  171. DEFUSERCMD("replace", 0, 0, void, do_replace, (void),)
  172. {
  173.     ULONG  rlen;
  174.     ULONG  flen;
  175.     Column col = Ep->column;
  176.  
  177.     rlen = strlen (Rstr);
  178.     flen = strlen (Fstr);
  179.  
  180.     text_sync ();
  181.  
  182.     /* Check whether replace-string does fit into the line */
  183.     if (rlen > flen && (Clen+rlen-flen) > MAXLINELEN-1)
  184.     {
  185. DEFMESSAGE( _FIND_line_2_long, "%s:\nLine too long" )
  186.     error (_FIND_line_2_long, av[0]);
  187.     } else
  188.     /* This checks whether the search-pattern does fit into
  189.     the current line at the current position !?!?! */
  190.        if (Clen >= col+flen)
  191.     {
  192.     /* Move rest of line. Make enough place for replace-string */
  193.     movmem (Current+col+flen, Current+col+rlen, Clen-col-flen+1);
  194.  
  195.     /* copy replace-string */
  196.     if (rlen)
  197.         movmem (Rstr, Current+col, rlen);
  198.  
  199.     /* correct line-length and position after symbol */
  200.     Clen       += rlen-flen;
  201.  
  202.     /* only if we search forward else stay on first char */
  203.     if (Srch_sign > 0)
  204.         Ep->column += rlen -1; /* one position left since we start
  205.                       at Ep->column+1 with searching */
  206.  
  207.     if (Clen < 0)
  208.         Clen = 0;
  209.  
  210.     if (Ep->column < 0)
  211.         Ep->column = 0;
  212.     }
  213.  
  214.     /* Check display, since we are not sure, whether the actual
  215.        position is visible on the screen */
  216.     if (!text_adjust (FALSE))
  217.     {
  218.     text_sync ();
  219.     text_redisplaycurrline ();
  220.     }
  221.  
  222. } /* do_replace */
  223.  
  224.  
  225. /******************************************************************************
  226.  
  227.     NAME
  228.     search_operation
  229.  
  230.     PARAMETER
  231.     Fstr        String to look for
  232.     Rstr        String to replace Fsrt with (if Doreplace != 0)
  233.     Doreplace   Replace Fstr with Rstr ?
  234.     Ep        Different fields in this structure
  235.  
  236.     DESCRIPTION
  237.     Searches in the text for Fstr and replaces it with Rstr if Doreplace is
  238.     true. If Ep->ignorecase is true, the string-search is case-insensitive
  239.     else not.
  240.  
  241.     For speed, I did replace the old function with this new one. The
  242.     routine works like Boyer-Moore search but I didn't find a good
  243.     explanation for it in books. You will find some for searching from the
  244.     beginning of a string but none if you try reverse. Sigh.
  245.  
  246. ******************************************************************************/
  247.  
  248. //#define DEBUG
  249. static UBYTE skip[256];         /* Distance for Boyer-Moore */
  250.  
  251. static void search_operation (void)
  252. {
  253.     UBYTE * ptr;
  254.     WORD    j;        /* Counter in Search-Pattern */
  255.     Column  col;    /* actual column */
  256.     Line    lin;    /* actual line */
  257.     UWORD   linlen; /* length of actual line */
  258.     UWORD   test;   /* result of case(in)sensitive compare */
  259.     ED      * ep;     /* actual editor */
  260.     int flen = strlen (Fstr);        /* Length of Search/Replace-String */
  261.  
  262.     if (!flen)
  263.     {             /* Error if nothing to look for. */
  264. DEFMESSAGE( _FIND_no_searchstring_defined, "%s:\nNo find pattern" )
  265.     error (_FIND_no_searchstring_defined, av[0]);
  266.     return;
  267.     }
  268.  
  269.     /* Note that we do not check for nothing to replace, since the user may
  270.        want to erase the full pattern */
  271.  
  272.     text_sync ();                    /* Save Current */
  273.  
  274.     ep = Ep;
  275.  
  276.     col = ep->column;            /* Actual column ... */
  277.     lin = ep->line;            /* ... and line */
  278.  
  279.     /* initskip() */
  280.     memset (skip, flen, sizeof (skip));  /* default: skip full length */
  281.  
  282.     if (Srch_sign > 0)
  283.     {     /* Search foreward */
  284.  
  285. // ADD WC-Search Part DELTA, here!
  286.     for (j=0; j<flen; j ++)
  287.     {
  288.         if (GETF_IGNORECASE(ep))
  289.         {
  290.         skip[tolower(Fstr[j])] =
  291.             skip[toupper(Fstr[j])] = flen-j-1;
  292.         } else
  293.         skip[Fstr[j]] = flen-j-1;
  294.     }
  295.  
  296.     ptr = GETTEXT(ep,lin);          /* Get line contents ... */
  297.     linlen = strlen (ptr);          /* ... and its length */
  298.     col ++;
  299.  
  300.     for (; ep; )
  301.     {
  302.         for (;;)
  303. // ADD WC-Search Part GAMMA, here!
  304.         {
  305.         /* This is the search-loop. Always remeber Boyer-Moore
  306.         begins comparing at the end and scans forward ! */
  307.         j = flen - 1;
  308.         col += j;
  309.  
  310.         /* Until reached beginning of search-string or EOL */
  311.         while (col < linlen)
  312.         {
  313.             /* if both are equal (case(in)sensitive) */
  314.             if (GETF_IGNORECASE(ep))
  315.             test = (tolower (ptr[col]) == tolower (Fstr[j]));
  316.             else
  317.             test = (ptr[col] == Fstr[j]);
  318.  
  319.             if (test)
  320.             {
  321.             if (!j) /* Full Match */
  322.                 goto found;
  323.  
  324.             col --; /* Next position */
  325.             j --;
  326.             } else
  327.             {     /* Determine skip-length */
  328.             if (flen-j >= skip[ptr[col]])
  329.                 j = flen - j;    /* length of match */
  330.             else
  331.                 j = skip[ptr[col]]; /* Adjust to char. */
  332.  
  333.             if (!j)
  334.             {
  335. printf ("search: infinite loop\n");
  336.                 return;
  337.             }
  338.  
  339.             col += j;
  340.  
  341.             j = flen - 1;    /* Restart j */
  342.             } /* Compare */
  343.         } /* while in line */
  344.  
  345.         lin ++;
  346.  
  347.         if (lin >= ep->lines)
  348.             break;
  349.  
  350.         ptr = GETTEXT(ep,lin);      /* Contents and Length */
  351.         linlen = strlen (ptr);
  352.         col = 0;
  353.         } /* while in text */
  354.  
  355.         if (!GETF_GLOBALSEARCH(ep))
  356.         break;
  357.  
  358.         if (ep = (ED *)GetSucc((struct Node *)ep))
  359.         {
  360.         lin = 0;
  361.         ptr = GETTEXT(ep,0);      /* Contents and Length */
  362.         linlen = strlen (ptr);
  363.         }
  364.     } /* for all editors */
  365.     } else
  366.     { /* Search backward */
  367.     for (j=flen-1; j>=0; j--)
  368.     {
  369.         if (GETF_IGNORECASE(ep))
  370.         {
  371.         skip[tolower(Fstr[j])] = j;
  372.         skip[toupper(Fstr[j])] = j;
  373.         } else
  374.         {
  375.         skip[Fstr[j]] = j;
  376.         }
  377.     }
  378.  
  379.     ptr = GETTEXT(ep,lin);          /* Get line contents ... */
  380.     linlen = strlen (ptr);          /* ... and its length */
  381.  
  382.     if (col >= linlen)  /* Beyound End-Of-Line ? */
  383.         col = linlen-flen;
  384.     else
  385.         col --;    /* don't find it right here if we are already on it */
  386.  
  387. D(bug("new search\n"));
  388.  
  389.     for (; ep; )
  390.     {
  391.         for (;;)
  392.         {
  393.         /* Same as above but reverse */
  394.         j = 0;
  395.  
  396.         while (col >= 0)
  397.         { /* Until BOL */
  398.             /* if both are equal (case(in)sensitive) */
  399.             if (GETF_IGNORECASE(ep))
  400.             test = (tolower (ptr[col]) == tolower (Fstr[j]));
  401.             else
  402.             test = (ptr[col] == Fstr[j]);
  403.  
  404. D(bug("[%s]\n[%s]\ncol %2ld j %2ld skip %2ld\n", ptr+col, Fstr+j, col, j,
  405.         skip[ptr[col]]));
  406.  
  407.             if (test)
  408.             {
  409.             j ++;
  410.             col ++; /* Next position */
  411.  
  412.             if (j == flen)
  413.             { /* Full Match */
  414.                 col -= flen;
  415.                 goto found;
  416.             }
  417.             } else
  418.             {     /* Determine skip-length */
  419.             /* j += j; */
  420.  
  421.             if (j < skip[ptr[col]])
  422.             {
  423.                 j = skip[ptr[col]]; /* Adjust to char. */
  424.             }
  425.             else
  426.                 j += flen;
  427.  
  428.             if (!j)
  429.             {
  430. printf ("search: infinite loop\n");
  431.                 return;
  432.             }
  433.  
  434.             col -= j;
  435.  
  436.             j = 0;     /* Restart j */
  437.             } /* Compare */
  438.  
  439. #if DEBUG
  440. {
  441.     char buf[41];
  442.  
  443.     strncpy (buf, &ptr[col], 40);
  444.     buf[35] = 0;
  445.  
  446.     printf ("Str '%6s'  Text '%s'  col=%2d j=%+d l=%3d\n", Fstr+j, buf, col, j, lin);
  447. }
  448. #endif
  449.         } /* while in line */
  450.  
  451.         /* Prev. line */
  452.         if (!lin)   /* Stop on 1. line */
  453.             break;
  454.  
  455.         lin --;
  456. D(bug("new line\n"));
  457.  
  458.         ptr = GETTEXT(ep,lin);      /* Contents and Length */
  459.         linlen = strlen (ptr);
  460.  
  461.         /* Last char. */
  462.         col = linlen-flen;
  463.         } /* while in text */
  464.  
  465.         if (!GETF_GLOBALSEARCH(ep))
  466.         break;
  467.  
  468.         if (ep = (ED *)GetPred((struct Node *)ep))
  469.         {
  470.         lin = ep->lines - 1;
  471.         ptr = GETTEXT(ep,lin);
  472.         col = linlen = strlen (ptr);
  473.         }
  474.     } /* for all editors */
  475.     } /* if foreward/backward */
  476.  
  477. DEFMESSAGE( _FIND_pattern_not_found, "%s:\nPattern `%s' not found" )
  478.     warn (_FIND_pattern_not_found, av[0], Fstr);
  479.     SETF_ABORTCOMMAND(ep,1);
  480.     return;
  481.  
  482. found:
  483.     if (ep != Ep)
  484.     {
  485.     switch_ed (ep);
  486.  
  487.     if (GETF_ICONMODE(ep))
  488.     {
  489.         uniconify ();
  490.     } else
  491.     {
  492.         /* Make window active */
  493.         WindowToFront (ep->win);
  494.         ActivateWindow (ep->win);
  495.  
  496.         set_window_params ();
  497.         window_title ();
  498.     }
  499.     }
  500.  
  501.     ep->line = lin;      /* Set Position */
  502.     ep->column = col;
  503.  
  504.     text_load ();        /* Copy Line into Current */
  505.  
  506.     if (Doreplace)
  507.     do_replace ();
  508.     else
  509.     text_adjust (FALSE);
  510. } /* search_operation */
  511.  
  512.  
  513. /******************************************************************************
  514. *****  ENDE search.c
  515. ******************************************************************************/
  516.  
  517. #if 0 // WildCard Search
  518.  
  519. // WC Search PART DELTA
  520.     if (!FLPttrnBuffer)
  521.  
  522.  
  523.  
  524. // WC Search PART GAMMA
  525. #define my_MatchPattern(ep,pt,str) (GETF_IGNORECASE(ep)? MatchPatternNoCase(pt,str): MatchPattern(pt, str))
  526.         // ---- since Dos.PatternMatch is not RegExr, we have no special
  527.         //    Patterns for SOL/EOL; for that reason, we must do some
  528.         //    additional matching;
  529.         //    imho, it would be better, we could call a subfunction
  530.         //    found = _matchpattern(line, pattern, &start, &len, from_back?, from_sol?, from_eol?);
  531.         //    but that function would need either an array of pattern,
  532.         //    or it needed global access to the different *PttrnBuffer =8-(
  533.  
  534.         if (FLPttrnBuffer) {
  535.             int ecol, ichar;
  536.             // ---- Match w/ prepended and postpended #? (only if 1/last!=^/$)
  537.             if (my_MatchPattern(ep, FLPttrnBuffer, ptr)) {
  538.             ecol = strlen (ptr);
  539.             if (!PLPttrnBuffer) {
  540.                 // ---- User wanted match of Full Line
  541.                 if (!col) {
  542.                 flen = ecol;
  543.                 goto found;
  544.                 } /* if */
  545.             } else {
  546.                 while (ptr[col]) {
  547.                 // ---- match w/ postpended #? (ony if last!=$)
  548.                 if (my_MatchPattern(ep, RLPttrnBuffer, ptr + col)) {
  549.                     if (!PttrnBuffer) {
  550.                     // ---- User wanted match up to EOL
  551.                     flen = ecol - col;
  552.                     goto found;
  553.                     } else {
  554.                     while (ecol >= col) {
  555.                         ichar = ptr [ecol];
  556.                         ptr[ecol] = 0;
  557.                         if (my_MatchPattern(ep, PttrnBuffer, ptr + col)) {
  558.                         flen = ecol - col;
  559.                         ptr[ecol] = ichar;
  560.                         // ---- Das hier geht verdammt tief in
  561.                         //    die Hose ... wir muessten etwas
  562.                         //    machen ala txt_replace(pos,rep,flen);
  563.                         //    so wird eindeutig die _falsche_
  564.                         //    Laenge ersetzt
  565.                         goto found;
  566.                         } /* if */
  567.                         ptr[ecol] = ichar;
  568.                         -- ecol;
  569.                     } /* while */
  570.                     } /* if */
  571.                 } /* if */
  572.                 ++ col;
  573.                 } /* while */
  574.             } /* if */
  575.             } /* if */
  576.  
  577.             ptr = GETTEXT(ep,lin);      /* Contents and Length */
  578.             linlen = strlen (ptr);
  579.             col = 0;
  580.         } else
  581.  
  582.  
  583.  
  584.  
  585.  
  586.  
  587.  
  588.  
  589. // WC Search Part Alpha
  590.  
  591. // start is an _input_and_result_!
  592. // end is a _input_and_result_!
  593.  
  594. // we _might_ have much _less_ problems, if we used strings, prepended and postpended with "\n"
  595. // that way we could just check for "\n" instead of that starnge way below
  596.  
  597. BOOL match_pattern (UBYTE *text, char **patterns, int *start, int *end, BOOL reverse, BOOL nocase)
  598. {
  599. #define loc_MatchPattern(ncs,pt,str) (ncs? MatchPatternNoCase(pt,str): MatchPattern(pt, str))
  600.     int    col,
  601.        ecol;
  602.     UBYTE *fl_pattern;
  603.     UYBTE *rl_pattern;
  604.     UBYTE *___pattern;
  605.     char   ichar;
  606.  
  607.     fl_pattern = patterns[0];
  608.     rl_pattern = patterns[1];
  609.     ___pattern = patterns[2];
  610.     col        = *start;
  611.     ecol       = *end;
  612.  
  613.     if (!reverse && col && !patterns[1])
  614.     return FALSE;
  615.  
  616.     ichar = ptr[ecol];
  617.     ptr[ecol] = 0;
  618.     if (loc_MatchPattern(ep, fl_pattern, ptr)) {
  619.     if (!rl_pattern) {
  620.         ptr[ecol] = ichar;
  621.         // ---- User wanted match of Full Line
  622.         if (reverse ? col : !col) {
  623.         *end   = ecol;
  624.         *start = 0;
  625.         return TRUE;
  626.         } /* if */
  627.         return FALSE;
  628.     } else {
  629.         while (reverse ? (col >= 0) : (ptr[col] != 0)) {
  630.         // ---- match w/ postpended #? (ony if last!=$)
  631.         if (loc_MatchPattern(ep, rl_pattern, ptr + col)) {
  632.             ptr[ecol] = ichar;
  633.             if (!___pattern) {
  634.             ptr[ecol] = ichar;
  635.             // ---- User wanted match up to EOL
  636.             if (!ichar) {
  637.                 *end   = ecol;
  638.                 *start =  col;
  639.                 return TRUE;
  640.             } /* if */
  641.             return FALSE;
  642.             } else {
  643.             while (ecol >= col) {
  644.                 if (loc_MatchPattern(ep, ___pattern, ptr + col)) {
  645.                 ptr[ecol] = ichar;
  646.                 *end   = ecol;
  647.                 *start =  col;
  648.                 return TRUE;
  649.                 } /* if */
  650.                 ptr[ecol] = ichar;
  651.                 --ecol;
  652.                 ichar     = ptr[ecol];
  653.                 ptr[ecol] = 0;
  654.             } /* while */
  655.             ptr[ecol] = ichar;
  656.             ecol      = *end;
  657.             ichar      = ptr[ecol];
  658.             ptr[ecol] = 0;
  659.             } /* if */
  660.         } /* if */
  661.         if (reverse)
  662.             -- col;
  663.         else
  664.             ++ col;
  665.         } /* while */
  666.     } /* if */
  667.     } /* if */
  668.     ptr[ecol] = ichar;
  669.     return FALSE;
  670. } /* match_pattern */
  671.  
  672.  
  673.  
  674.  
  675. #endif
  676.